package gomz.res;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;


/**
 * Diese Klasse Message beinhaltet die Objekte, die zwischen dem Client und dem Server versendet werden.
 * @author Schatzmann
 *
 */
public class Message {
// ********************************************************************************
// Enum
// ********************************************************************************
	/**
	 * Enum, der den Typ des Objektes definiert
	 */
	public enum ObjectTyp {
        //einzelne Objekte
		Hexagram, //save oder get
        Question, //save, delete, get
        User, //save, delete, get, logout
        
        //Collections
        HexagramCore, //getAll
        Category, //getAll, save, delete *** auch einzelne objekte moeglich fuer save und delete mit index 0
        QuestionCore, //getAll
        UserCore, //login oder getAll *** auch einzelne objekte moeglich fuer login mit index 0

	};
	/**
	 * Enum der Aktion, die mit diesem Objekt ausgefuehrt werden soll
	 */
	public enum ActionTyp {
		Save, SaveAll, Get, GetAll, Delete, Login, Logout, Success, Fail, OutOfConnections
	};
	
// ********************************************************************************
// Variablen
// ********************************************************************************
        //ObjTyp und ActionTyp
	@Element(required = true)
	private ObjectTyp objectTyp;
    @Element(required = true)
    private ActionTyp actionTyp;

    //Einzelne Objekte
    @Element(required = false)
	private Hexagram hexagram;
    @Element(required = false)
	private Question question;
	@Element(required = false)
	private User user;
        
    //Collections
    @ElementList (required=false)
	private ArrayList<HexagramCore> hexagramCoreCollection;
    @ElementList (required=false)
	private ArrayList<Category> categoryCollection;
    @ElementList (required=false)
	private ArrayList<QuestionCore> questionCoreCollection;
	@ElementList (required=false)
	private ArrayList<UserCore> userCoreCollection;

	
// ********************************************************************************
// Getter/Setter
// der ObjectTyp wird automatisch im setter gesetzt, abhängig vom Object
// der ActionTyp muss beim Konstruktor angegeben werden
// ********************************************************************************
        
        //*******ObjectTyp und ActionTyp*******
        //ObjectTyp
	public ObjectTyp getObjectTyp() {
		return objectTyp;
	}
        public void setObjectTyp(ObjectTyp objectTyp) {
		this.objectTyp = objectTyp;
	}
        
        
        //ActionTyp
	public ActionTyp getActionTyp() {
                return actionTyp;
        }
        public void setActionTyp(ActionTyp actionTyp) {
                this.actionTyp = actionTyp;
        }
        
 
        //*******Einzelne Objekte*******
        //Hexagram
	public Hexagram getHexagram() {
		return hexagram;
	}
	public void setHexagram(Hexagram hexagram) {
		clearMsg();
		this.hexagram = hexagram;
		this.objectTyp = ObjectTyp.Hexagram;
	}
        
        
    //Question
    public Question getQuestion() {
	return question;
	}
	public void setQuestion(Question question) {
		clearMsg();
		this.question = question;
		this.objectTyp = ObjectTyp.Question;
	}
        
        
    //User
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		clearMsg();
		this.user = user;
		this.objectTyp = ObjectTyp.User;
	}
        

    //*******Collections*******
    //HexagramCoreCollection
    public ArrayList<HexagramCore> getHexagramCoreCollection() {
	return hexagramCoreCollection;
	}
	public void setHexagramCoreCollection(ArrayList<HexagramCore> hexagramCoreCollection) {
		clearMsg();
		this.hexagramCoreCollection = hexagramCoreCollection;
		this.objectTyp = ObjectTyp.HexagramCore;
	}
        
        
        //CategoryCollection
	public ArrayList<Category> getCategoryCollection() {
		return categoryCollection;
	}
	public void setCategoryCollection(ArrayList<Category> categoryCollection) {
		clearMsg();
		this.categoryCollection = categoryCollection;
		this.objectTyp = ObjectTyp.Category;
	}
        
              
        //QuestionCoreCollection
        public ArrayList<QuestionCore> getQuestionCoreCollection() {
		return questionCoreCollection;
	}
        public void setQuestionCoreCollection(ArrayList<QuestionCore> questionCore) {
		clearMsg();
		this.questionCoreCollection = questionCore;
		this.objectTyp = ObjectTyp.QuestionCore;
	}
	

	//UserCoreCollection
	public ArrayList<UserCore> getUserCoreCollection() {
		return userCoreCollection;
	}
	public void setUserCoreCollection(ArrayList<UserCore> userCoreCol) {
		clearMsg();
		this.userCoreCollection = userCoreCol;
		this.objectTyp = ObjectTyp.UserCore;
	}


// ********************************************************************************
// Konstruktor
// Der ActionTyp muss immer angegeben werden
// der ObjectTyp wird automatisch im setter gesetzt, abhängig vom Object
// ********************************************************************************
	public Message(@Element(name = "actionTyp") ActionTyp actionType1){
		this.actionTyp = actionType1;
	}
	
// ********************************************************************************
// Methoden
// ********************************************************************************
	
	/**
	 * Diese Methode formatiert den Inhalt der Klasse in XML und sendet es ueber den mitgegebenen Socket.
	 * @param socket Socket ueber welchen gesendet werden soll	
	 * @throws Exception Falls die uebertragung fehlschlaegt.
	 */
	public void send(Socket socket) throws Exception {	
		Serializer netOut = new Persister();
		OutputStream out = socket.getOutputStream();
		netOut.write(this, out);
		out.write('\n');
		out.flush();         
	}
	
	/**
	 * Diese Methode gibt eine Message klasse zurueck, die vom Socket erhalten wurde.
         * Muss static sein da dass Message Objekt noch nicht besteht und erst empfangen werden muss
	 * @param socket Socket welches die Nachricht vom Server empfaengt
	 * @return Message Die erhaltene Nachricht
	 * @throws Exception Falls die uebertragung fehlschlaegt.
	 */
	public static Message receive(Socket socket) throws Exception {
		Serializer netIn = new Persister();
		InputStream in = socket.getInputStream();
		Message msg = netIn.read(Message.class, in);
		return msg;
	}
	
	/**
	 * Diese Methode loescht den Inhalt, der uebertragen werden soll. Dies verhindert,
	 * dass es vergessen wird und unoetiges uebertragen wird, da jeweils nur ein Objekt
	 * gesendet werden soll.
	 */
	private void clearMsg(){
            	this.hexagram = null;
                this.question = null;
                this.user = null;
                this.hexagramCoreCollection = null;
                this.categoryCollection = null;
                this.questionCoreCollection = null;
                this.userCoreCollection = null;
	}
}